package com.example.demo.demos.web.ehcache;

import org.apache.ibatis.builder.InitializingObject;
import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.config.builders.*;
import org.ehcache.config.units.EntryUnit;
import org.ehcache.event.EventType;
import org.ehcache.expiry.ExpiryPolicy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.Duration;

public class DelegeteEhCache implements org.apache.ibatis.cache.Cache, InitializingObject {
    private Logger log = LoggerFactory.getLogger(DelegeteEhCache.class);
    private boolean logFlag = false;
    private boolean noExpiration = false;

    public boolean isNoExpiration() {
        return noExpiration;
    }

    public void setNoExpiration(boolean noExpiration) {
        this.noExpiration = noExpiration;
    }

    /**
     * The cache instance.
     */
    protected Cache cache;
    /**
     * The cache manager reference.
     */
    protected static CacheManager CACHE_MANAGER = CacheManagerBuilder.newCacheManagerBuilder()
            .build(true);

    private String id;
    private long timeToIdleSeconds = 0;
    private long timeToLiveSeconds = 0;
    private long maxEntriesLocalHeap = 10000;
    private long maxEntriesLocalDisk = 1;
    private String memoryStoreEvictionPolicy;

    @Override
    public void initialize() throws Exception {
        ExpiryPolicy mepf = ExpiryPolicyBuilder.noExpiration();
        if (!noExpiration) {
            if (timeToIdleSeconds == 0 && timeToLiveSeconds == 0) {
                timeToIdleSeconds = 600;
            }
            if (timeToLiveSeconds > 0 && timeToIdleSeconds > 0) {
                if (timeToIdleSeconds > timeToLiveSeconds) {
                    timeToIdleSeconds = 0;
                } else {
                    timeToLiveSeconds = 0;
                }
            }
            mepf = timeToLiveSeconds > 0 ? ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(timeToLiveSeconds))
                    : ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofSeconds(timeToIdleSeconds));
        }
// 2. 单独配置 Cache A：最多 1000 个条目
        CacheConfigurationBuilder<Object, Object> config =
                CacheConfigurationBuilder.newCacheConfigurationBuilder(
                        Object.class, Object.class,
                        ResourcePoolsBuilder.newResourcePoolsBuilder().heap(maxEntriesLocalHeap, EntryUnit.ENTRIES) // ✅ 限制为 1000 个条目
                ).withExpiry(mepf);
        CacheEventListenerConfigurationBuilder cacheEventListenerConfiguration = CacheEventListenerConfigurationBuilder
                .newEventListenerConfiguration(new ListenerObject(), EventType.CREATED, EventType.UPDATED, EventType.EVICTED, EventType.EXPIRED, EventType.REMOVED)
                .unordered().asynchronous();
        config = config.withService(cacheEventListenerConfiguration);
// 4. 创建缓存（各自独立上限）
        cache = CACHE_MANAGER.createCache(id, config);
        if (logFlag) {
            log.info("cache3 init id:" + id);
        }
    }


    /**
     * {@inheritDoc}
     */
    @Override
    public void clear() {
        cache.clear();
        if (logFlag) {
            log.info("cache3 init id:" + id);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getId() {
        if (logFlag) {
            log.info("cache3 getId id:" + id);
        }
        return id;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Object getObject(Object key) {
        if (logFlag) {
            log.info("cache3 getObject key:" + key);
        }
        return cache.get(key);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int getSize() {
        if (logFlag) {
            log.info("cache3 getSize id:" + id);
        }
        return Math.toIntExact(cache.spliterator().estimateSize());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void putObject(Object key, Object value) {
        if (logFlag) {
            log.info("cache3 putObject key:" + key);
        }
        cache.put(key, value);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Object removeObject(Object key) {
        if (logFlag) {
            log.info("cache3 removeObject key:" + key);
        }
        Object obj = getObject(key);
        cache.remove(key);
        return obj;
    }

    public boolean isLogFlag() {
        return logFlag;
    }

    public void setLogFlag(boolean logFlag) {
        this.logFlag = logFlag;
    }

    public void setId(String id) {
        this.id = id;
    }

    public long getTimeToIdleSeconds() {
        return timeToIdleSeconds;
    }

    public void setTimeToIdleSeconds(long timeToIdleSeconds) {
        this.timeToIdleSeconds = timeToIdleSeconds;
    }

    public long getTimeToLiveSeconds() {
        return timeToLiveSeconds;
    }

    public void setTimeToLiveSeconds(long timeToLiveSeconds) {
        this.timeToLiveSeconds = timeToLiveSeconds;
    }

    public long getMaxEntriesLocalDisk() {
        return maxEntriesLocalDisk;
    }

    public void setMaxEntriesLocalDisk(long maxEntriesLocalDisk) {
        this.maxEntriesLocalDisk = maxEntriesLocalDisk;
    }

    public long getMaxEntriesLocalHeap() {
        return maxEntriesLocalHeap;
    }

    public void setMaxEntriesLocalHeap(long maxEntriesLocalHeap) {
        this.maxEntriesLocalHeap = maxEntriesLocalHeap;
    }

    public String getMemoryStoreEvictionPolicy() {
        return memoryStoreEvictionPolicy;
    }

    public void setMemoryStoreEvictionPolicy(String memoryStoreEvictionPolicy) {
        this.memoryStoreEvictionPolicy = memoryStoreEvictionPolicy;
    }
}
